using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using Services;
using SpaceBattle.Logic.SampleLevel;
using System.IO.IsolatedStorage;
using System.IO;
using Utilities.Menu.UIElements;
using SpaceBattle.Resources;

namespace SpaceBattle.Menu
{
    using Game = Microsoft.Xna.Framework.Game;

    public class SlideScreen : Microsoft.Xna.Framework.DrawableGameComponent
    {
        //public event Action OnTransitionEnd;
        //public event Action OnTransitionStart;
        //static readonly int NUM_SLIDES = 8;
        readonly float TRANSITION_TIME = 1;
        SpriteBatch SpriteBatch;
        ContentManager Content { get { return Game.Content; } }

        Matrix screen_transform;
        Texture2D [] slides;
        String [] slides_paths;

        int current_slide, next_slide;
        float transitionTimer;

        String[] texts;
        String exit_message_title, exit_message;
        String button_yes_label, button_no_label;
        Action onYes, onNo;

        InputManager input_service;
        SoundEffectInstance click;


        public SlideScreen(Game game, String [] slides_paths, String[] slide_descriptions)
            : this(game, slides_paths, slide_descriptions, null, null, null, null, null, null)
        {
            //this.UpdateOrder = (int)ComponentOrders.TRANSITION+1;
            //this.DrawOrder = (int)ComponentOrders.UI;

            //this.texts = slide_descriptions;
            //this.slides_paths = slides_paths;
            
        }

        public SlideScreen(Game game, String[] slides_paths, String[] slide_descriptions, 
            string exit_message_title, string exit_message, string button_yes_label,
            string button_no_label, Action onYes, Action onNo)
            : base(game)
        {
            this.UpdateOrder = (int)ComponentOrders.TRANSITION + 1;
            this.DrawOrder = (int)ComponentOrders.UI;

            this.texts = slide_descriptions;
            this.slides_paths = slides_paths;

            this.exit_message_title = exit_message_title;
            this.exit_message = exit_message;
            this.onYes = onYes;
            this.onNo = onNo;

            this.button_no_label = button_no_label;
            this.button_yes_label = button_yes_label;
        }

        //public SlideScreen(Game game)
        //    : base(game)
        //{
        //    this.UpdateOrder = (int)ComponentOrders.TRANSITION + 1;
        //    this.DrawOrder = (int)ComponentOrders.UI;
        //}


        protected override void OnEnabledChanged(object sender, EventArgs args)
        {
            base.OnEnabledChanged(sender, args);
        }

        Texture2D next_texture, prev_texture, back_texture, mask, white, menu_bar;
        Button next, prev, back, message_yes, message_no;
        SpriteFont text_font, title_font;
         
        protected override void LoadContent()
        {
            //texts = new String[NUM_SLIDES];
            //slides = new Texture2D[NUM_SLIDES];

            if (slides_paths != null)
            {
                slides = new Texture2D[slides_paths.Length];
                for (int i = 0; i < Math.Min(slides_paths.Length,2); i++)
                {
                    //slides[i - 1] = Content.Load<Texture2D>("Tutorial/Slide " + i);
                    slides[i] = Content.Load<Texture2D>(slides_paths[i]);
                }
            }

            prev_texture = Content.Load<Texture2D>("Menu/arrow");
            back_texture = Content.Load<Texture2D>("Menu/upper_right_x");
            mask = Content.Load<Texture2D>("Tutorial/TutorialMask");
            white = Content.Load<Texture2D>("UI/WhitePixel");
            menu_bar = Game.Content.Load<Texture2D>("UI/pause_menu_border");

            text_font = Content.Load<SpriteFont>("Fonts/Arial18Ptx");
            title_font = Content.Load<SpriteFont>("Fonts/OCRAExtended24");

            click = Content.Load<SoundEffect>("Audio/button").CreateInstance();

            var rect = new Rectangle(800 - prev_texture.Width - 20, 240-prev_texture.Height/2, prev_texture.Width, prev_texture.Height);
            next = new Button()
            {
                CollisionBox = rect,
                Position = new Vector2(rect.X, rect.Y)
            };

            rect = new Rectangle(20, 240-prev_texture.Height/2, prev_texture.Width, prev_texture.Height);
            prev = new Button()
            {
                CollisionBox = rect,
                Position = new Vector2(rect.X, rect.Y)
            };

            rect = new Rectangle(GraphicsDevice.Viewport.Width - back_texture.Width, 0, back_texture.Width, back_texture.Height);
            back = new Button()
            {
                CollisionBox = rect,
                Position = new Vector2(rect.X, rect.Y)
            };

            if (exit_message != null)
            {
                rect = new Rectangle((int)(target_slide_screen.Right - title_font.MeasureString(button_yes_label).X - 40), 400, 100, 70);
                message_yes = new Button()
                {
                    CollisionBox = rect,
                    Position = new Vector2(rect.X, rect.Y)
                };

                rect = new Rectangle(target_slide_screen.X + 40, 400, 100, 70);
                message_no = new Button()
                {
                    CollisionBox = rect,
                    Position = new Vector2(rect.X, rect.Y)
                };
            }
            splitText(texts[current_slide], text_font, new Rectangle(60, 375, 680, 95), ALIGN.CENER);

            base.LoadContent();

            if (slides_paths != null)
            {
                new System.Threading.Thread(new ThreadStart(
                () =>
                {
                    for (int i = 2; i < slides_paths.Length; i++)
                    {
                        slides[i] = Content.Load<Texture2D>(slides_paths[i]);
                    }
                })).Start();
            }
        }

        public override void Initialize()
        {
            SpriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            input_service = Game.Services.GetService(typeof(IInputManager)) as InputManager;
            if (input_service == null)
            {
                input_service = new InputManager(Game);
                Game.Components.Add(input_service);
            }
            input_service.OnTap += new InputManager.Tap(on_tap);
            input_service.OnFlick += new InputManager.Flick(on_flick);

            screen_transform = Matrix.CreateScale(Game.GraphicsDevice.Viewport.Width / SpaceBattleGame.DEFAULT_SCR_WIDTH,
    Game.GraphicsDevice.Viewport.Height / SpaceBattleGame.DEFAULT_SCR_HEIGHT, 1.0f);
            base.Initialize();
        }


        protected override void Dispose(bool disposing)
        {
            input_service.OnTap -= new InputManager.Tap(on_tap);
            input_service.OnFlick -= new InputManager.Flick(on_flick);
            base.Dispose(disposing);
        }

        bool dispose=false;
        float message_alpha = 0;
        public override void Update(GameTime gameTime)
        {
            
            if (current_slide != next_slide && !show_exit_message)
            {
                if (TRANSITION_TIME <= transitionTimer)
                {
                    current_slide = next_slide;
                    splitText(texts[current_slide], text_font, new Rectangle(60, 375, 680, 95), ALIGN.CENER);
                }
                else
                    transitionTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
            }

            //per non propagare il back button agli altri componenti attivi       
            if (show_exit_message || exit_message==null)
            {
                if (dispose)
                {
                    if (open <= 0)
                        this.Dispose();

                    open -= (float)gameTime.ElapsedGameTime.TotalSeconds;
                }
                else
                {
                    dispose = input_service.IsBackButtonPressed();
                    open = Math.Min(1, open + (float)gameTime.ElapsedGameTime.TotalSeconds);
                    message_alpha = Math.Min(1, message_alpha + (float)gameTime.ElapsedGameTime.TotalSeconds);
                }
            }
            else
            {
                show_exit_message = input_service.IsBackButtonPressed();
                if (show_exit_message)
                {
                    splitExitMessage();
                }
                open = Math.Min(1, open + (float)gameTime.ElapsedGameTime.TotalSeconds);
            }

            base.Update(gameTime);
        }

        bool show_exit_message;
        float open = 0;
        int open_start_up = 400 - 8, open_start_down = 400 + 8;
        Rectangle target_slide_screen = new Rectangle(100, 10, 600, 360),
            start_slide_screen = new Rectangle(400, 240-8, 600, 16);

        public override void Draw(GameTime gameTime)
        {
            SpriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, screen_transform);

            var yposition = (int)MathHelper.Lerp(start_slide_screen.Y, target_slide_screen.Y, open);
            var heigt = (int)MathHelper.Lerp(start_slide_screen.Height, target_slide_screen.Height, open);

            var r = new Rectangle(100, yposition, 600, heigt);
            
            SpriteBatch.Draw(white, GraphicsDevice.Viewport.Bounds, Color.White*0.05f*open);
            SpriteBatch.Draw(mask, r, Color.White);
            
            if(open>=1)
                if (show_exit_message)
                {
                    if (message_alpha >= 1)
                    {
                        SpriteBatch.DrawString(title_font, button_no_label, message_no.Position, Color.White);
                        SpriteBatch.DrawString(title_font, button_yes_label, message_yes.Position, Color.White);
                    }
                    for (int i = 0; i < rows.Count; i++)
                    {
                        SpriteBatch.DrawString(rows[i].font, rows[i].text, rows[i].position, Color.White * open * message_alpha);
                    }
                }
                else
                    if (current_slide != next_slide)
                    {
                        DrawBlendingInAndOutTransition(r);

                    }
                    else
                    {
                        SpriteBatch.Draw(slides[current_slide], r, Color.White);

                        //var mr = new Rectangle(r.X - 2, r.Y, r.Width + 4, 8);
                        ////mr.Height=8;
                        ////mr.Y -= 8;
                        //SpriteBatch.Draw(menu_bar, mr, Color.White);
                        //mr.Y = r.Bottom-8;
                        //SpriteBatch.Draw(menu_bar, mr, null, Color.White, 0, Vector2.Zero, SpriteEffects.FlipVertically, 1);
                        for (int i = 0; i < rows.Count; i++)
                        {
                            SpriteBatch.DrawString(rows[i].font, rows[i].text, rows[i].position, Color.White * open);
                        }
                    }



            SpriteBatch.Draw(prev_texture, next.CollisionBox,null, Color.White * (next_slide < slides.Length - 1 && !show_exit_message? 1 : 0.5f), 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 1);
            SpriteBatch.Draw(prev_texture, prev.CollisionBox, null, Color.White * (next_slide > 0 && !show_exit_message? 1 : 0.5f));

            SpriteBatch.Draw(back_texture, back.CollisionBox, Color.White);
                        
            SpriteBatch.End();

            base.Draw(gameTime);
        }

        void DrawBlendingInAndOutTransition(Rectangle r)
        {
        
            SpriteBatch.Draw(slides[current_slide], r, Color.White * (float)Math.Cos(MathHelper.PiOver2*(transitionTimer/TRANSITION_TIME)));
            SpriteBatch.Draw(slides[next_slide], r, Color.White * (float)Math.Sin(MathHelper.PiOver2 * (transitionTimer / TRANSITION_TIME)));
        }

       
        void on_flick(Vector2 delta)
        {
            if (delta.X < 500)
                nextSlide();
            else
                if (delta.X > -500)
                    prevSlide();
        }

        void on_tap(Vector2 tap_position)
        {
            bool tapped = true;
            if (next.CollisionBox.Contains((int)tap_position.X, (int)tap_position.Y))
                tapped = nextSlide();
            else if (prev.CollisionBox.Contains((int)tap_position.X, (int)tap_position.Y))
                tapped = prevSlide();
            else if (back.CollisionBox.Contains((int)tap_position.X, (int)tap_position.Y))
            {
                if (exit_message == null || show_exit_message)
                    dispose = true;
                else
                {
                    splitExitMessage();
                    show_exit_message = true;
                }
            }
            else if (message_yes.CollisionBox.Contains((int)tap_position.X, (int)tap_position.Y) && show_exit_message)
            {
                onYes();
                dispose = true;
            }
            else if (message_no.CollisionBox.Contains((int)tap_position.X, (int)tap_position.Y) && show_exit_message)
            {
                onNo();
                dispose = true;
            }
            else
                tapped = false;
            if(tapped&&!(click.State == SoundState.Playing)) 
                click.Play();
    
        }

        private bool nextSlide()
        {
            if (next_slide == slides.Length - 1 || slides[next_slide + 1] == null || show_exit_message)
                return false;
            if (next_slide != current_slide)
                current_slide = next_slide;
            transitionTimer = 0;
            rows.Clear();
            next_slide++;// = Math.Min(next_slide + 1, slides.Length - 1);
            return true;
        }
        private bool prevSlide()
        {
            if (next_slide == 0 || slides[next_slide-1]==null || show_exit_message)
                return false;
            if (next_slide != current_slide)
                current_slide = next_slide;
            transitionTimer = 0;
            rows.Clear();
            next_slide--;// = Math.Max(next_slide - 1, 0);
            return true;
        }

        struct row
        {
            public string text;
            public SpriteFont font;
            public Vector2 position;
        }



        private void splitExitMessage()
        {
            var r = target_slide_screen;
            r.X += 20;
            r.Width -= 40;
            r.Height = r.Height / 3;
            rows.Clear();
            splitText(exit_message_title, title_font, r, ALIGN.CENER);
            r.Y = r.Y + (int)(r.Height);
            r.Height *= 2;
            splitText(exit_message, text_font, r, ALIGN.CENER);
        }



        enum ALIGN { RIGHT, LEFT, CENER };
        List<row> rows = new List<row>();
        void splitText(string text, SpriteFont font, Rectangle box, ALIGN align)
        {
            //rows.Clear();
            var  righe = new List<string>();
            //var prev_label_count = rows.Count;
            var frasi = text.Split(new string[] { @"\n" }, StringSplitOptions.None);
            for (int r = 0; r < frasi.Length; r++)
            {
                var frase = frasi[r];

                var ls = frase.Split(new char[] { ' ' });
                var c_l = "";
                for (int i = 0; i < ls.Length; i++)
                {
                    var l = " " + ls[i];
                    //while (font.MeasureString(l).X >= box.Width)
                    //{
                    //    l = l.Substring(0, l.Length / 2) + "..";
                    //}
                    if (font.MeasureString(c_l + l).X < box.Width)
                        c_l += l;
                    else
                    {
                        righe.Add(c_l);
                        c_l = "";
                        i--;
                    }
                }
                if (!c_l.Equals("")) righe.Add(c_l);
            }

            for (int i = 0; i < righe.Count; i++)
            {
                var l = righe[i];
                var pos = new Vector2();
                switch (align)
                {
                    case ALIGN.LEFT: 
                        pos = new Vector2(box.X,
                      box.Y + box.Height / 2 + ((i - righe.Count / 2) * (font.MeasureString("I").Y)) - font.MeasureString("I").Y / 2);
                        break;
                    case ALIGN.CENER:
                        pos = new Vector2(
                            box.X+(box.Width-font.MeasureString(l).X)/2,
                     box.Y + box.Height / 2 + ((i - righe.Count / 2) * (font.MeasureString("I").Y)) - font.MeasureString("I").Y / 2);
                        break; 
                }
                rows.Add(new row() { position = pos + Vector2.One * 2.0f, text = l, font=font });
            }

        }
    
    }
}